﻿namespace Mercury.ParticleEngine.EmitterVisualizer
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using Mercury.ParticleEngine.EmitterShapes;

    /// <summary>
    /// A simple implementation of the emitter base class for visualization.
    /// </summary>
    public sealed class VisualizerParticleEmitter : ParticleEmitter
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Mercury.ParticleEngine.EmitterVisualizer.VisualizerParticleEmitter"/>
        /// class.
        /// </summary>
        /// <param name="capacity">The maximum number of particles which may be managed by the
        /// emitter at any given time.</param>
        /// <param name="term">The period of time in whole and fractional seconds that particles
        /// will remain active for.</param>
        public VisualizerParticleEmitter(Int32 capacity, TimeSpan term, IEmitterShape shape, IStateManager stateManager)
            : base(capacity, term, shape, stateManager)
        {
            var type = typeof(ParticleEmitter);

            _size = capacity;
            _head = type.GetField("_head", BindingFlags.Instance | BindingFlags.NonPublic);
            _next = type.GetField("_next", BindingFlags.Instance | BindingFlags.NonPublic);
            _buffer = type.GetField("_buffer", BindingFlags.Instance | BindingFlags.NonPublic);
        }

        private readonly FieldInfo _head;
        private readonly FieldInfo _next;
        private readonly FieldInfo _buffer;

        private readonly Int32 _size;

        public Int32 Head
        {
            get { return (Int32)_head.GetValue(this); }
        }

        public Int32 Next
        {
            get { return (Int32)_next.GetValue(this); }
        }

        public MetaParticle[] Buffer
        {
            get { return (MetaParticle[])_buffer.GetValue(this); }
        }

        public unsafe MetaParticle[] ParticlesNorm()
        {
            var list = new List<MetaParticle>();

            if (ActiveParticlesCount > 0)
            {
                fixed (MetaParticle* buffer = Buffer)
                {
                    var iterator = new MetaParticleIterator(buffer, _size, Head, ActiveParticlesCount);

                    var meta = iterator.First;

                    do
                    {
                        list.Add(*meta);
                    } while (iterator.MoveNext(&meta));
                }
            }

            return list.ToArray();
        }
    }
}